#include "utils/file/ShaderReader.h"

#include "render/RendererAPI.h"
#include "render/Shader.h"

#include "render/OpenGL/OpenGLShader.h"

namespace Cogs {
	std::shared_ptr<Shader> Shader::Load(const std::string& name,
		const std::unordered_map<ShaderType, std::string>& shaderTypeAndFilePath) 
	{
		switch (RendererAPI::GetAPIType()) {
			case RendererAPIType::OpenGL: {
				std::unordered_map<ShaderType, std::string> shaderTypeAndSorce;
				for (const auto& [type, filePat] : shaderTypeAndFilePath) {
					shaderTypeAndSorce[type] = ReadFileToString(filePat);
				}
				return Create(name, shaderTypeAndSorce);
			}

			case RendererAPIType::None: {
				__debugbreak();
				return nullptr;
			}

			default: {
				return nullptr;
			}
		}
	}

	std::shared_ptr<Shader> Shader::Create(const std::string& name, 
		const std::unordered_map<ShaderType, std::string>& shaderTypeAndSorce) 
	{
		switch (RendererAPI::GetAPIType()) {
			case RendererAPIType::OpenGL: {
				std::shared_ptr<OpenGLShader> shaderOpenGL = std::make_shared<OpenGLShader>(name);
				shaderOpenGL->AttachShaderFromSource(shaderTypeAndSorce);
				shaderOpenGL->Link();
				return shaderOpenGL;
			}
			
			case RendererAPIType::None: {
				__debugbreak();
				return nullptr;
			}

			default: {
				return nullptr;
			}
		}
	}

	void ShaderLibrary::Add(const std::string& name, const std::shared_ptr<Shader>& shader){
		if (Exists(name)) {
			return;
		}
		m_Shaders[name] = shader;
	}

	void ShaderLibrary::Add(const std::shared_ptr<Shader>& shader) {
		auto& name = shader->GetName();
		Add(name, shader);
	}

	std::shared_ptr<Shader> ShaderLibrary::Load(const std::string& name,
		const std::unordered_map<ShaderType, std::string>& shaderTypeAndFilePath)
	{
		std::shared_ptr<Shader> shader = Shader::Load(name, shaderTypeAndFilePath);
		Add(name, shader);
		return shader;
	}

	std::shared_ptr<Shader> ShaderLibrary::Create(const std::string& name,
		const std::unordered_map<ShaderType, std::string>& shaderTypeAndSorce) 
	{
		std::shared_ptr<Shader> shader = Shader::Create(name, shaderTypeAndSorce);
		Add(name, shader);
		return shader;
	}

	std::shared_ptr<Shader> ShaderLibrary::Get(const std::string& name) {
		if (!Exists(name)) {
			return nullptr;
		}
		return m_Shaders[name];
	}

	bool ShaderLibrary::Exists(const std::string& name) {
		return m_Shaders.count(name);
	}
}